#include "flash.h"
#include "stm32f10x.h"
#include "stm32f10x_spi.h"
#include "drivers.h"

#define FLASH_NOSELECT()      GPIO_SetBits(GPIOB, GPIO_Pin_12)
#define FLASH_SELECT()        GPIO_ResetBits(GPIOB, GPIO_Pin_12)

void flash_spi_init(void)
{
    SPI_InitTypeDef spi;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
    FLASH_NOSELECT();
    spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    spi.SPI_Mode = SPI_Mode_Master;
    spi.SPI_DataSize = SPI_DataSize_8b;
    spi.SPI_CPOL = SPI_CPOL_High;
    spi.SPI_CPHA = SPI_CPHA_2Edge;
    spi.SPI_NSS = SPI_NSS_Soft;
    spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
    spi.SPI_FirstBit = SPI_FirstBit_MSB;
    spi.SPI_CRCPolynomial = 7;
    SPI_Init(SPI2, &spi);
    SPI_Cmd(SPI2, ENABLE);
}

void flash_gpio_init(void)
{
    GPIO_InitTypeDef gpio;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
    //config spi2 sck miso mosi
    gpio.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    gpio.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &gpio);

    //config spi2 cs pin
    gpio.GPIO_Pin = GPIO_Pin_12;
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    gpio.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &gpio);
}

void flash_init(void)
{
    flash_gpio_init();
    flash_spi_init();
    logi("Flash id = %08x", flash_read_id());
}

uint8_t flash_spi_read(void)
{
    uint8_t read;

    /* 等待发送缓冲区空 */
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);

    /* 发送一个字节 */
    SPI_I2S_SendData(SPI2, 0);

    /* 等待数据接收完毕 */
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);

    /* 读取接收到的数据 */
    read = SPI_I2S_ReceiveData(SPI2);

    /* 返回读到的数据 */
    return read;
}

void flash_spi_write(uint8_t byte)
{
    /* 等待发送缓冲区空 */
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);

    /* 发送一个字节 */
    SPI_I2S_SendData(SPI2, byte);

    /* 等待数据接收完毕 */
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);

    /* 读取接收到的数据 */
    SPI_I2S_ReceiveData(SPI2);
}

uint32_t flash_read_id(void)
{
    uint32_t id;
    uint8_t id1, id2, id3;

    FLASH_SELECT();
    flash_spi_write(RDID_FLASH);
    id1 = flash_spi_read();
    id2 = flash_spi_read();
    id3 = flash_spi_read();
    FLASH_NOSELECT();

    id = ((uint32_t)id1 << 16) | ((uint32_t)id2 << 8) | id3;

    return id;
}

uint8_t flash_read_state(void)
{
    uint8_t temp = 0;

    FLASH_SELECT();
    flash_spi_write(RDSR_FLASH);
    temp = flash_spi_read();
    FLASH_NOSELECT();
    return temp;
}

uint8_t flash_write_state(uint8_t data)
{
    if(flash_write_enable() == FALSE)
        return FALSE;

    FLASH_SELECT();
    flash_spi_write(WRSR_FLASH);
    flash_spi_write(data);
    FLASH_NOSELECT();
    return TRUE;
}

uint8_t flash_write_enable(void)
{
    uint8_t temp;

    FLASH_SELECT();
    flash_spi_write(WREN_FLASH);
    FLASH_NOSELECT();

    temp = flash_read_state();
    if(temp & 0x02)
        return TRUE;
    else
        return FALSE;
}

uint8_t flash_read_busy(void)
{
    uint8_t temp = flash_read_state();

    if(temp & 0x01)
        return TRUE;
    else
        return FALSE;
}

uint8_t flash_write_data(uint8_t sector_addr, uint8_t page_addr,
        uint8_t byte_addr, uint16_t num, uint8_t *data)
{
    uint16_t i;

    if(num == 0)
        return FLASH_OP_ZERO;

    i = 100;
    while(1) {
        if(0 == flash_read_busy())
            break;
        os_delay_ms(10);
        i --;
        if(i == 0)
            return FLASH_OP_BUSY;
    }
    if(FALSE == flash_write_enable())
        return FLASH_OP_FAIL;

    FLASH_SELECT();
    flash_spi_write(PP);
    flash_spi_write(sector_addr);
    flash_spi_write(page_addr);
    flash_spi_write(byte_addr);
    for(i = 0; i < num; i++) {
        flash_spi_write(*(data + i));
    }
    FLASH_NOSELECT();
    return FLASH_OP_DONE;
}

uint8_t flash_read_data(uint8_t sector_addr, uint8_t page_addr,
        uint8_t byte_addr, uint16_t num, uint8_t *data)
{
    uint16_t i;

    if(num == 0)
        return FLASH_OP_ZERO;

    i = 100;
    while(1) {
        if(0 == flash_read_busy())
            break;
        os_delay_ms(10);
        i --;
        if(i == 0)
            return FLASH_OP_BUSY;
    }

    FLASH_SELECT();
    flash_spi_write(READ_FLASH);
    flash_spi_write(sector_addr);
    flash_spi_write(page_addr);
    flash_spi_write(byte_addr);
    for(i = 0; i < num; i++) {
        *(data + i) = flash_spi_read();
    }
    FLASH_NOSELECT();
    return FLASH_OP_DONE;
}

uint8_t flash_erase_sector(uint8_t sector_addr)
{
    uint16_t i;

    i = 100;
    while(1) {
        if(0 == flash_read_busy())
            break;
        os_delay_ms(10);
        i --;
        if(i == 0)
            return FLASH_OP_BUSY;
    }
    if(FALSE == flash_write_enable())
        return FLASH_OP_FAIL;

    FLASH_SELECT();
    flash_spi_write(READ_FLASH);
    flash_spi_write(0);
    flash_spi_write(0);
    FLASH_NOSELECT();
    i = 40;
    while(1) {
        if(FALSE == flash_read_busy())
            break;
        os_delay_ms(10);
        i --;
        if(i == 0)
            return FLASH_OP_BUSY;
    }
    return FLASH_OP_DONE;
}

uint8_t flash_erase_all(void)
{
    uint16_t i;

    i = 100;
    while(1) {
        if(0 == flash_read_busy())
            break;
        os_delay_ms(10);
        i --;
        if(i == 0)
            return FLASH_OP_BUSY;
    }
    if(FALSE == flash_write_enable())
        return FLASH_OP_FAIL;

    FLASH_SELECT();
    flash_spi_write(BE);
    FLASH_NOSELECT();
    return FLASH_OP_DONE;
}

